package org.example.encrypt.interceptor;

import cn.hutool.core.util.ReflectUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.example.encrypt.common.MybatisCryptHandler;
import org.springframework.stereotype.Component;

import java.sql.PreparedStatement;
import java.util.Properties;

/**
 * 加密拦截器：只拦截参数处理器
 *
 * @Author WeiBing
 * @Create 2024/8/12 18:02
 */
@Slf4j
@Component
@Intercepts(
        {
                @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
        }
)
@RequiredArgsConstructor
public class MybatisEncryptInterceptor implements Interceptor {

    private final MybatisCryptHandler handler;

    /**
     * 拦截器拦截到对象后的处理逻辑
     */
    @Override
    public Object intercept(Invocation invocation) {
        return invocation;
    }

    /**
     * 判断是否拦截这个类型对象（根据@Intercepts注解决定），然后决定是返回一个代理对象还是返回原对象。
     * 在实现plugin方法时，要判断一下目标类型，如果是我们期望处理的类型，那么就拦下了，执行我们自己的处理。否则的话，直接返回目标本身。
     * 备注：每经过一个拦截器对象都会调用插件的plugin方法，也就是说，该方法会调用4次。根据@Intercepts注解来决定是否生成代理对象。
     */
    @SneakyThrows
    @Override
    public Object plugin (Object target) {
        if (target instanceof ParameterHandler) {
            // 获取当前操作类型
            MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(target, "mappedStatement");
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
            // 对请求参数进行加密操作
            handler.parameterEncrypt((ParameterHandler)target, sqlCommandType);
        }
        return target;

    }

    /**
     * 拦截器需要一些变量对象，而且这个对象是支持可配置的。
     * 暂时没啥用
     */
    @Override
    public void setProperties (Properties properties) {
    }

}
